package com.yangquan.threadPool;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class EnhancedCallerRunsPolicy implements RejectedExecutionHandler {
    private static final Logger logger = LoggerFactory.getLogger(EnhancedCallerRunsPolicy.class);
    private final long retryTimeout; // 重试入队的超时时间（毫秒）
    private final boolean logOnRetrySuccess; // 是否记录重试成功日志

    public EnhancedCallerRunsPolicy(long retryTimeout) {
        this(retryTimeout, false); // 默认不记录重试成功日志
    }

    public EnhancedCallerRunsPolicy(long retryTimeout, boolean logOnRetrySuccess) {
        this.retryTimeout = retryTimeout;
        this.logOnRetrySuccess = logOnRetrySuccess;
    }

    @Override
    public void rejectedExecution(Runnable task, ThreadPoolExecutor executor) {
        // 检查线程池是否已关闭
        if (executor.isShutdown()) {
            logger.debug("线程池已关闭，拒绝任务: {}", task);
            return;
        }

        // 第一步：尝试重新入队
        try {
            BlockingQueue<Runnable> queue = executor.getQueue();
            // 尝试在超时时间内重新入队
            boolean enqueued = queue.offer(task, retryTimeout, TimeUnit.MILLISECONDS);
            
            if (enqueued) {
                if (logOnRetrySuccess) {
                    logger.info("任务重新入队成功: {}", task);
                }
                return; // 入队成功，结束处理
            }
        } catch (InterruptedException e) {
            // 中断处理：恢复中断状态并继续后续处理
            Thread.currentThread().interrupt();
            logger.warn("重试入队时被中断，将转由调用者执行任务: {}", task);
        }

        // 第二步：入队失败，由调用者线程执行
        logger.warn("任务重新入队失败，由调用者线程执行: {}", task);
        try {
            task.run();
            logger.debug("调用者线程成功执行任务: {}", task);
        } catch (Throwable t) {
            logger.error("调用者执行任务失败: {}", task, t);
            throw new RejectedExecutionException("调用者执行任务失败", t);
        }
    }
}